#ifndef _IGSLIB_IEXTERNAL_BOARD_INCLUDE_
#define _IGSLIB_IEXTERNAL_BOARD_INCLUDE_

#include <vector>
#include <igslib_iserial_manager.h>

namespace igslib
{
    struct IExternalBoard;
    struct IExternalBoardEvent
    {
        /*!
         * 當狀態發生變化時觸發。
         * @param a0 事件容器(擁有者)。
         * @param a1 進度指示。
         */
        virtual void OnUpgradeProcess(IExternalBoard*,float)=0;
    };

    /*!
     * 在外接板上可嵌入一顆保護單元(IC)，用來確保外接板與遊戲可綁在一起，互相認證。
     */
    struct IProtectUnit:public IComponent
    {
        enum class State
        {
            Idle,                    //!< 可接收要求。
            WaitDeposit,             //!< 已接受用戶存入資料要求，等待回應確認。
            WaitWithdraw,            //!< 已接受用戶提領資料要求，等待回應確認。
            WaitAuthentication,      //!< 已接受用戶身份認證要求，等待回應確認。
			WaitIKVWork,      //!< 初始化IKV 元件，等待回應確認。
            Disconnect,              //!< 無溝通回應，可能已發生錯誤。
        };
        /*!
         * 對於有些回應速度不快的IC，可實作此介面先行送出要求，
         * 讓保護IC可先執行指令，用戶可再利用GetState()取得狀態，
         * 以便確認是否可呼叫其他操作，像是ReadData()或WriteData()。
         * @param a0 要求名稱，依實作需求而定。
         * @param a1 要求參數，依實作需求而定。
         * @return true表示接受要求。
         * @note
         *     以IKV的實作為例，用戶若要提領安全性資料，需經過下列流程：
         *
         *         std::vector<char> addresses;
         *         addresses.push_back(0); // 表示要提領0號位址上的資料。
         *         bool request_ok = SendRequest("withdraw",addresses);
         *         if (request_ok)
         *         {
         *             if (GetState() == State::Idle)
         *             {
         *                 std::vector<char> security_data = Withdraw();
         *             }
         *         }
         *      
         *      上述範例中，GetState()可能不會馬上回傳State::Idle，用戶需自行持續更新，
         *      以確認安全資料已經抵達。
         *
         *      IKV的實作中，可使用的要求名稱及所需參數如下：
         *      - withdraw,提領位址編號(由0起算),1byte.。
         *      - deposit,提領位址編號(由0起算),1byte.。
         *      - authenticate,無。
         */
		 
        virtual bool SendRequest(const std::string&,const std::vector<char>&) = 0;
        /*!
         * 提領記錄在保護IC中安全的資料。
         * @return 記錄在保護IC中安全的資料。
         */
        virtual std::vector<char> Withdraw() = 0;
        /*!
         * 存入資料進保護IC安全區。
         * @param a0 要存入之資料。
         */
        virtual void Deposit(const std::vector<char>&) = 0;
        /*!
         * 進行身份認證。
         * @return true表示身份認證通過。
         */
        virtual bool Authenticate() = 0;
        /*!
         * 取得目前狀態。
         * @return 目前狀態。
         */
        virtual State GetState() = 0;
		/*!
         * 初始化IKV 
         */	 
        virtual void ProtectEnable() = 0;
		/*!
         * 將安全性資料封死，無法再行更改。
         */	 
		virtual void Seal()=0;
        /*!
         * 若實作是使用SPI通訊介面，用此函式輸入SPI的實作。
         * @param a0 SPI的實作。
         */	 
        virtual void SetSPI(ISpi*)=0;
		
    };
    /*!
     * 外接板操作介面。
     * 「外接板」*通常*是I/O板(也有可能是別的)，此介面定義了常見的一些操作，像是如何取得版本號或保險絲是否有燒斷等。
     */
    struct IExternalBoard:public IComponent
    {
         virtual IProtectUnit* GetProtectUnit() = 0;

        /*!
         * 取得指定編號之保險絲是否已燒斷。
         * @return true表示已燒斷。
         */
        virtual bool GetFuseState(int)=0;
		/*!
         * 取得燒錄檔的版本號字串。
         * @return 燒錄檔的版本號字串。若發生錯誤則會傳回"ERROR"字串。
         */
        virtual std::string GetSourceVersion()=0;
        /*!
         * 取得顯示用的版本號字串。
         * @return 顯示用的版本號字串。若發生錯誤則會傳回"ERROR"字串。
         */
        virtual std::string GetVersion()=0;
		 /*!
         * 設定燒錄檔的絕對路徑與檔名
         */
        virtual void SetSourceDst(const std::string&)=0;
        /*!
		 * 載入燒錄檔進行解析
         * @param a0 RawData。
         * @param a1 length of RawData。
         */
        virtual void ImportRawData(char*,int)=0;	
		/*!
         * 更新韌體程式。
         * @warning 這是同步式動作，若更新未結束前不會離開函式執行，有錯誤的話會丟出例外，請注意。
         * @return
         *     0: 操作正常。
         *     -1: 抹除逾時。
         *     -2: 抹除失敗。
         *     -3: 載入逾時。
         *     -4: 載入失敗。
         *     -5: 寫入逾時。
         *     -6: 寫入失敗。
         *     -7: 關閉逾時。
         *     -8: 關閉失敗。
         *     -9: 開檔失敗。
         *     -10: 沒有任何資料來源。
         */
        virtual int Upgrade()=0;
        /*!
         * 設定相關事件處理者。
         * @param a0 相關事件處理者。
         */
        virtual void SetEventHandler(IExternalBoardEvent*) = 0;
        /*!
         * 更新資訊。
         */
        virtual void Update()=0;
        /*!
         * 若實作是使用SPI通訊介面，用此函式輸入SPI的實作。
         * @param a0 SPI的實作。
         */
        virtual void SetSPI(ISpi*)=0;
        /*!
         * 若實作是使用UART通訊介面，用此函式輸入UART的實作。
         * @param a0 UART的實作。
         */
        virtual void SetUART(IUart*)=0;
    };
    /*!
     * 外接板管理層。
     */
    struct IExternalBoardManager:public IManager<IExternalBoard*>
    {
        /*!
         * 創建MH主板上的MCU資源。
         * @return MH主板上的MCU資源。
         * @note
         *     因應韌體更新功能，使用者需呼叫SetUART()導入通訊介面的實作。
         */
        virtual IExternalBoard* New_MH_MCU()=0;
        /*!
         * 創建MH主板上根據專案特規實作MCU資源。
         * @param a0 專案名。
         * @return 根據專案特規實作MCU資源。
         *     nullptr：創建失敗。
         *     other：實作指標。
         * @note
         *     因應韌體更新功能，使用者需呼叫SetUART()導入通訊介面的實作。
         *     因應保護單元認證功能，使用者需呼叫SetSPI()導入通訊介面的實作。
         *
         *     目前已實作專案名對照如下：
         *     "DragonBallRaceMH"：龍珠賽球
		 *     "DragonBallRaceLU1P"：龍珠賽球
		 *     "DragonBallRaceLU2P"：龍珠賽球
         */
        virtual IExternalBoard* New_ProjMCU(const std::string&)=0;
    };
};

extern "C"{
    igslib::IExternalBoardManager* GetExternalBoardManagerInstance();
};
#endif
